package cn.sh.library.mgts.service.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
import org.elasticsearch.action.bulk.BulkProcessor;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetMappingsRequest;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import cn.sh.library.mgts.common.Constant;
import cn.sh.library.mgts.service.IndexService;

@Service
public class IndexServiceImpl implements IndexService {
	@Autowired
	@Qualifier("bulkProcessor")
	BulkProcessor bulkProcessor;

	@Autowired
	RestHighLevelClient highLevelClient;

	private static Logger logger = LoggerFactory.getLogger(IndexServiceImpl.class);

	@Override
	public boolean createIndex(String indexName, String mappings, String settings) throws IOException {
		CreateIndexRequest request = new CreateIndexRequest(indexName);

		// settings
//		request.settings(Settings.builder() 
//			    .put("index.number_of_shards", 3)
//			    .put("index.number_of_replicas", 2)
//			    .put("index.max_result_window", 50000)
//			);
		if (StringUtils.isNotEmpty(settings)) {
			request.settings(settings, XContentType.JSON);
		}

		// mappings
		if (StringUtils.isNotEmpty(mappings)) {
			request.mapping(mappings, XContentType.JSON);
		}

		try {
			CreateIndexResponse createIndexResponse = highLevelClient.indices().create(request, RequestOptions.DEFAULT);
			boolean acknowledged = createIndexResponse.isAcknowledged();
			return acknowledged;
		} catch (ElasticsearchException e) {
			logger.error("索引[{}]创建失败", indexName);
			logger.error(e.getMessage());
		}
		return false;
	}

	@Override
	public boolean delIndex(String indexName) {
		try {
			DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
			return highLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT).isAcknowledged();
		} catch (Exception e) {
			logger.error("索引[{}]删除失败", indexName);
			logger.error(e.getMessage());
		}

		return false;
	}

	@Override
	public boolean putMappings(String indexName, String mappings) {
		try {
			PutMappingRequest putMapping = new PutMappingRequest(indexName);
			putMapping.source(mappings, XContentType.JSON);

			return highLevelClient.indices().putMapping(putMapping, RequestOptions.DEFAULT).isAcknowledged();
		} catch (Exception e) {
			logger.error("索引[{}]添加,mappings失败", indexName);
			logger.error(e.getMessage());
		}

		return false;
	}

	@Override
	public Map<String, Object> getMappings(String indexName, String property) {
		try {
			GetMappingsRequest getMappings = new GetMappingsRequest();
			getMappings.indices(indexName);
			Map<String, MappingMetaData> allMappings = highLevelClient.indices()
					.getMapping(getMappings, RequestOptions.DEFAULT).mappings();
			if (StringUtils.isEmpty(property)) {
				Map<String, Object> map = new HashMap<String, Object>();
				allMappings.forEach((key, value) -> {
					map.put(key, value.getSourceAsMap());
				});
				return map;
			} else {
				return allMappings.get(property).getSourceAsMap();
			}
		} catch (Exception e) {
			logger.error("索引[{}]获取mappings失败", indexName);
			logger.error(e.getMessage());
		}
		return new HashMap<String, Object>();
	}



	@Override
	public boolean createOrUpdateDoc(String indexName, String content, String id, String routing,String refresh) {
		try {
			IndexRequest request = new IndexRequest(indexName);//indexRequest属于覆盖  有就覆盖  没有就添加  updateRequest对已有索引属性的增改
			request.id(id).source(content, XContentType.JSON);
			if (StringUtils.isNotEmpty(routing)) {
				request.routing(routing);
			}
			if (StringUtils.isNotEmpty(refresh)) {
				request.setRefreshPolicy(refresh);
			}
			IndexResponse indexResponse = highLevelClient.index(request, RequestOptions.DEFAULT);
			return true;
		} catch (Exception e) {
			logger.error("在索引[{}]中创建id[{}]失败", indexName, id);
			logger.error(e.getMessage());
		}
		return false;
	}

	@Override
	public boolean createOrUpdateDoc(String indexName, Map<String, Object> content, String id, String routing,String refresh) {
		try {
			IndexRequest request = new IndexRequest(indexName);
			request.id(id).source(content);
			if (StringUtils.isNotEmpty(routing)) {
				request.routing(routing);
			}
			if (StringUtils.isNotEmpty(refresh)) {
				request.setRefreshPolicy(refresh);
			}
			IndexResponse indexResponse = highLevelClient.index(request, RequestOptions.DEFAULT);
			return true;
		} catch (Exception e) {
			logger.error("在索引[{}]中创建id[{}]失败", indexName, id);
			logger.error(e.getMessage());
		}
		return false;
	}

	@Override
	public boolean delDoc(String indexName, String id, String routing,String refresh) {
		try {
			DeleteRequest deleteRequest = new DeleteRequest(indexName, id);
			if (StringUtils.isNotEmpty(routing)) {
				deleteRequest.routing(routing);
			}
			if (StringUtils.isNotEmpty(refresh)) {
				deleteRequest.setRefreshPolicy(refresh);
			}
			DeleteResponse deleteResponse = highLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
			if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
				logger.error("在索引[{}]中删除id[{}]失败, 索引不存在", indexName, id);
				return false;
			}
			return true;
		} catch (Exception e) {
			logger.error("在索引[{}]中删除id[{}]失败", indexName, id);
			logger.error(e.getMessage());
		}

		return false;
	}

	@Override//有就比较属性 属性有就更新 没有就添加
	public boolean updateDoc(String indexName, String id, String content, String routing,String refresh) {
		try {
			UpdateRequest updateRequest = new UpdateRequest(indexName, id);
			updateRequest.doc(content, XContentType.JSON);
//			request.upsert(content, XContentType.JSON);
			if (StringUtils.isNotEmpty(routing)) {
				updateRequest.routing(routing);
			}
			if (StringUtils.isNotEmpty(refresh)) {
				updateRequest.setRefreshPolicy(refresh);
			}
			UpdateResponse updateResponse = highLevelClient.update(updateRequest, RequestOptions.DEFAULT);
//			if (updateResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
//				logger.error("在索引[{}]中修改id[{}]失败, 索引不存在", indexName, id);
//			    return false;
//			}
			return true;
		} catch (Exception e) {
			logger.error("在索引[{}]中修改id[{}]失败", indexName, id);
			logger.error(e.getMessage());
		}

		return false;
	}

	@Override
	public boolean updateDoc(String indexName, String id, Map<String, Object> content, String routing,String refresh) {
		try {
			UpdateRequest updateRequest = new UpdateRequest(indexName, id);
			updateRequest.doc(content, XContentType.JSON);
			if (StringUtils.isNotEmpty(routing)) {
				updateRequest.routing(routing);
			}
			if (StringUtils.isNotEmpty(refresh)) {
				updateRequest.setRefreshPolicy(refresh);
			}
			UpdateResponse updateResponse = highLevelClient.update(updateRequest, RequestOptions.DEFAULT);
//			if (updateResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
//				logger.error("在索引[{}]中修改id[{}]失败, 索引不存在", indexName, id);
//			    return false;
//			}
			return true;
		} catch (Exception e) {
			logger.error("在索引[{}]中修改id[{}]失败", indexName, id);
			logger.error(e.getMessage());
		}

		return false;
	}

	@Override
	public Map<String, Object> getDoc(String indexName, String id, String routing) {
		try {
			GetRequest getRequest = new GetRequest(indexName, id);
			if (StringUtils.isNotEmpty(routing)) {
				getRequest.routing(routing);
			}
			GetResponse getResponse = highLevelClient.get(getRequest, RequestOptions.DEFAULT);

			if (getResponse.isExists()) {
//			    long version = getResponse.getVersion();
//			    String sourceAsString = getResponse.getSourceAsString(); 
				Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
				sourceAsMap.put("_id", getResponse.getId());
				return sourceAsMap;
			} else {
				logger.error("在索引[{}]中获取id[{}]失败, 不存在", indexName, id);
			}
		} catch (Exception e) {
			logger.error("在索引[{}]中获取id[{}]失败", indexName, id);
			logger.error(e.getMessage());
		}
		return new HashMap<String, Object>();
	}

	@Override
	public List<Map<String, Object>> getData(String indexName, String userJson) {
		try {
			SearchSourceBuilder builder = new SearchSourceBuilder();
			BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
			queryBuilder.should(QueryBuilders.wildcardQuery("userId", "*" + userJson + "*"))
					.should(QueryBuilders.matchPhraseQuery("userName", userJson));
			builder.query(queryBuilder);
			List<Map<String, Object>> res = new ArrayList<>();

			SearchRequest searchRequest = new SearchRequest(Constant.BIB_HORIZON_USER);
			searchRequest.source(builder);
			SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
			searchResponse.getHits().forEach(action -> {
				Map<String, Object> viewMap = new HashMap<>();
				viewMap = action.getSourceAsMap();
				res.add(viewMap);
			});
			return res;
		} catch (Exception e) {
			logger.error("在索引[{}]中获取id[{}]失败", indexName, userJson);
			logger.error(e.getMessage());
		}

		return new ArrayList<>();
	}
	
	//禁检词
	@Override
	public List<Map<String, Object>> getBannedWordsData(String indexName, String json) {
		try {
			SearchSourceBuilder builder = new SearchSourceBuilder();
			BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
			queryBuilder.should(QueryBuilders.matchPhraseQuery("bannedWords", json));
			builder.query(queryBuilder);
			List<Map<String, Object>> res = new ArrayList<>();

			SearchRequest searchRequest = new SearchRequest(Constant.BIB_HORIZON_BANNEDWORDS);
			searchRequest.source(builder);
			SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
			searchResponse.getHits().forEach(action -> {
				Map<String, Object> viewMap = new HashMap<>();
				viewMap = action.getSourceAsMap();
				res.add(viewMap);
			});
			return res;
		} catch (Exception e) {
			logger.error("在索引[{}]中获取id[{}]失败", indexName, json);
			logger.error(e.getMessage());
		}
		return new ArrayList<>();
	}

	@Override
	public boolean getBannedWordsMatching(String indexName,String json) {
		String[] text = json.trim().replaceAll( "\\s+", " " ).split(" ");
		try {
			SearchSourceBuilder builder = new SearchSourceBuilder();
			BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
			for(int i=0;i<text.length;i++) {
				queryBuilder.should(QueryBuilders.termQuery("bannedWords.keyword", text[i]));//完全匹配
			}
			builder.query(queryBuilder);
			List<Map<String, Object>> res = new ArrayList<>();

			SearchRequest searchRequest = new SearchRequest(Constant.BIB_HORIZON_BANNEDWORDS);
			searchRequest.source(builder);
			SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
			searchResponse.getHits().forEach(action -> {
				Map<String, Object> viewMap = new HashMap<>();
				viewMap = action.getSourceAsMap();
				res.add(viewMap);
			});
			if(res.size()>0) {
				return false;
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return true;
	}
	
	@Override
	public Map<String, Object> getAll(String indexName, String routing) {
		try {
			GetRequest getRequest = new GetRequest(indexName);
			if (StringUtils.isNotEmpty(routing)) {
				getRequest.routing(routing);
			}
			GetResponse getResponse = highLevelClient.get(getRequest, RequestOptions.DEFAULT);
			if (getResponse.isExists()) {
				Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
				return sourceAsMap;
			} else {
				logger.error("在索引[{}]中获取id[{}]失败, 不存在", indexName);
			}
		} catch (Exception e) {
			logger.error("在索引[{}]中获取id[{}]失败", indexName);
			logger.error(e.getMessage());
		}
		return new HashMap<String, Object>();
	}


	@Override
	public boolean createOrUpdateDoc(String indexName, String content, String routing,String refresh) {
		try {
			IndexRequest request = new IndexRequest(indexName);//indexRequest属于覆盖  有就覆盖  没有就添加  updateRequest对已有索引属性的增改
			request.source(content, XContentType.JSON);
			if (StringUtils.isNotEmpty(routing)) {
				request.routing(routing);
			}
			if (StringUtils.isNotEmpty(refresh)) {
				request.setRefreshPolicy(routing);
			}
			bulkProcessor.add(request);
			IndexResponse indexResponse = highLevelClient.index(request, RequestOptions.DEFAULT);
			return true;
		} catch (Exception e) {
			logger.error("在索引[{}]中创建id[{}]失败", indexName);
			logger.error(e.getMessage());
		}
		bulkProcessor.flush();
		return false;
	}


	@Override
	public boolean delDoc(String indexName,String id, String routing) {
		try {
			
			DeleteRequest deleteRequest = new DeleteRequest(indexName, id);
			if (StringUtils.isNotEmpty(routing)) {
				deleteRequest.routing(routing);
			}
			bulkProcessor.add(deleteRequest);
			DeleteResponse deleteResponse = highLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
			if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
				logger.error("在索引[{}]中删除id[{}]失败, 索引不存在", indexName, id);
				return false;
			}
			return true;
		} catch (Exception e) {
			logger.error("在索引[{}]中删除id[{}]失败", indexName, id);
			logger.error(e.getMessage());
		}
		bulkProcessor.flush();
		return false;
	}
	
	
	@Override 
	public boolean refreshIndices(String... indices) {
		try {
		    RefreshRequest request = new RefreshRequest(indices);
		    highLevelClient.indices().refresh(request, RequestOptions.DEFAULT);
		} catch (ElasticsearchException exception) {
			if (exception.status() == RestStatus.NOT_FOUND) {
				return true;
		    }
			return false;
		} catch (IOException e) {
			logger.error("在索引[{}]中刷新失败", indices);
			return false;
		}
		
		return true;
	}


}
